package pricingTag;

/*
 * what function should be implemented in store object?
 * 1) generate deal;
 * 2) consider a deal;
 * 
 * 
 */

import java.util.*;

public class Store {
	// what attributes should a store has?
	Global global;
	String store_name;
	int id;
	LinkedList<Product> products;
	int num_customers;
	int deal_maximum_consider_time = 10;

	public Store(String name, Global global) {
		this.global = global;
		this.store_name = name;
		this.id = Global.store_id++;
		products = new LinkedList<Product>();
	}

	// create a deal, without specific to storeu
	// not finished
	Deal generate_deal(String product_name) {
		Product product = this.find_product(product_name);
		if (product == null) {
			System.out.println(this + " doesn't have " + product_name);
		}
		/*
		 * how to decide increase price: 1)start with the maximum? 2) start with
		 * lowest?
		 */
		double increase_price = this
				.compute_maximum_effective_increase_price(product);
		double bonus = this.compute_bonus(product, increase_price);

		Deal deal = new Deal(this, product_name, bonus, increase_price);
		this.global.broadcast_deal(deal);
		return deal;
	}

	// simple version: suppose when save more than 30%, people will always buy
	// my product, need modification
	double compute_maximum_effective_increase_price(Product product) {
		double x = 0.3 * product.price;
		// System.out.println("maximus increase" );
		return x;
	}

	/*
	 * how to decide the bonus? must limited by the expected gains of this deal;
	 * not finished
	 */
	double compute_bonus(Product product, double increase_price) {

		// return 0.5 * this.compute_maximum_bonus(product, increase_price);
		return 0.5 * this.compute_benefit(product, increase_price);

	}

	// maximum benefit, that is, all the goods are sold by myself
	double compute_maximum_bonus(Product product, double increase_price) {
		double increased_ratio = increase_price / product.price;
		int increased_selling = this.compute_increased_selling(product,
				increased_ratio);
		// set the bonus to be half the benefit of this deal right now, need
		// modified;
		double bonus = (increased_selling * product.benefit);
		return bonus;
	}

	// decrease the asked bonus every time the deal is reconsidered
	// need modification.
	double compute_asked_bonus(Product product, Deal deal) {
		double loss = this.compute_loss(product, deal.increase_price);
		// don't know other's benefit, so suppose if other's increase such, what
		// benefit should I get?
		double potential_benefit = this.compute_bonus(product,
				deal.increase_price);
		double asked_bonus = Math.pow(0.5, 2) * potential_benefit + loss;
		return asked_bonus;

	}

	/*
	 * consider a reply: 1) stop the negotiation of a deal 2) update the bonus
	 * of the deal and send it back(need modification)
	 */
	Deal consider_reply(Reply reply) {
		Deal deal = reply.deal;
		if (reply.deal.from_store.equals(this)) {
			if (deal.to_store_accpet) {
				System.out.println("deal made!!!!!!!!!!!!!!!");
				deal.show();
				return null;
			}

			if (deal.count > this.deal_maximum_consider_time) {
				System.out.println("stop this deal");
				this.stop_deal(deal);
				return null;
			}

			// how to decide the new bonus?
			// should I consider the asked bonus?
			// or just increase the old bonus?
			double new_bonus = this.compute_new_bonus(
					this.find_product(deal.product_name), deal);
			deal.bonus = new_bonus;
			deal.to_store = reply.from_store;
			this.global.send_deal_to(reply.from_store, deal);
			return deal;
		} else {
			return null;
		}

	}

	double compute_new_bonus(Product product, Deal deal) {
		// System.out.println("old bonus is " + deal.bonus);
		double remaining_benefit = this.compute_maximum_bonus(product,
				deal.increase_price) - deal.bonus;
		double new_bonus = deal.bonus + 0.5 * remaining_benefit;
		// System.out.println("new bonus is " + new_bonus);
		return (new_bonus);
	}

	// need modification
	void stop_deal(Deal deal) {

	}

	// compute the expected increased selling, still use 30% as an threshold.
	// need modification
	int compute_increased_selling(Product product, double increased_ratio) {
		int increased_selling = 0;
		int maximum_increased = this.global.find_product_record(product.name).totalSelling
				- product.numSelling;
		if (increased_ratio >= 0.3) {
			increased_selling = maximum_increased;

		} else {
			increased_selling = (int) ((increased_ratio / 0.3) * maximum_increased);
		}
		// System.out.println("increase selling " + increased_selling
		// + " by increase " + increased_ratio);
		return increased_selling;
	}

	Product find_product(String product_name) {
		for (Product product : this.products) {
			if (product.name.equals(product_name)) {
				return product;
			}
		}
		return null;
	}

	/*
	 * based on what should a store accept a deal? 1) should has this product 2)
	 * bonus is bigger than loss caused by increasing price need modification.
	 */
	Reply generate_reply(Deal deal) {
		deal.show();
		if (deal.from_store == this) {
			// System.out
			// .println("------------Error:  this deal is from myself!----------");
			return null;
		}
		Product product = this.find_product(deal.product_name);
		if (product == null) {

			// Reply r = new Reply(this, deal);
			// r.has_product = false;
			return null;
		}
		double asked_bonus = this.compute_asked_bonus(product, deal);

		Reply reply = new Reply(this, deal);
		if (deal.bonus >= asked_bonus) {
			reply.accept = true;
			deal.to_store_accpet = true;
			this.global.send_reply_to(deal.from_store, reply);
		} else {
			reply.asked_bonus = asked_bonus;
			this.global.send_reply_to(deal.from_store, reply);

		}
		return reply;

		// double loss = compute_loss(product, deal.increase_price);
		// double asked_bonus = loss
		// + this.compute_bonus(product,
		// this.compute_maximum_effective_increase_price(product));
		//
		// if (loss < deal.bonus) {
		// Reply r = new Reply(this, deal);
		// deal.to_store_accpet = true;
		// r.accept = true;
		// this.global.send_reply_to(deal.from_store, r);
		// return r;
		// } else {
		// Reply r = new Reply(this, deal);
		// /*
		// * very generous version, just require the loss as bonus should
		// * promise a deal to be made if it can be
		// */
		// // r.asked_bonus = loss;
		//
		// this.global.send_reply_to(deal.from_store, r);
		//
		// return r;
		// }
	}

	/*
	 * compute the loss of increase the price of certain product loss = number
	 * of decreased selling * benefit per selling
	 */
	double compute_loss(Product product, double increase_price) {
		double loss = product.benefit
				* this.comupte_loss_of_selling(product, increase_price);
		// System.out.println(this.store_name + " by incressing the price of "
		// + increase_price + " the loss is " + loss);

		return loss;
	}

	/*
	 * a simple Demand Price Elasticity:if more than 30%, selling zero. other
	 * wise, linearly decrease. need modification
	 */
	int comupte_loss_of_selling(Product product, double increased_price) {
		double increased_ratio = increased_price / product.price;
		int lossOfSelling = 0;
		if (increased_ratio >= 0.3) {
			lossOfSelling = product.numSelling;
		} else {
			lossOfSelling = (int) (increased_ratio / 0.3 * product.numSelling);
		}
		// System.out.println(this.store_name + " by incressing the price of "
		// + increase_price + " the loss of selling is " + lossOfselling);
		return lossOfSelling;
	}

	void show_products() {
		System.out.println(this + " product: ");
		for (Product product : this.products) {
			System.out.println(product);
		}
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "Store \"" + this.store_name + "\"";
	}

	void show() {
		System.out.println(this.store_name);
	}

	double compute_benefit_from_deal(Deal deal) {
		Product product = this.find_product(deal.product_name);
		double increase_price = deal.increase_price;
		return this.compute_benefit(product, increase_price);
	}

	double compute_benefit(Product product, double increase_price) {
		double increased_ratio = increase_price / product.price;
		int increased_selling = this.compute_increased_selling(product,
				increased_ratio);
		// set the bonus to be half the benefit of this deal right now, need
		// modified;
		double benefit = (increased_selling * product.benefit);
		return benefit;
	}

	/*
	 * broadcast the deal, get a list of replies on this deal
	 */
	// LinkedList<Reply> broadcastDeal(Deal deal) {
	// LinkedList<Reply> replies = new LinkedList<Reply>();
	//
	// for (Store store : this.global.stores) {
	// if (store != deal.from_store) {
	// Reply reply = store.generate_reply(deal);
	// replies.add(reply);
	// }
	// }
	// return replies;
	// }

	Reply sendToStore(Store store, Deal deal) {
		Reply reply = store.generate_reply(deal);
		return reply;
	}

	double compute_benefit_from_product(Product product) {
		return product.benefit * product.numSelling;
	}

	void show_benefit_from_deal(Deal deal) {
		Product product = this.find_product(deal.product_name);
		double old_benefit = this.compute_benefit_from_product(product);
		System.out.print("Store " + this.store_name + " old benefit = "
				+ old_benefit);
		if (this.equals(deal.from_store)) {
			double new_benefit = this.compute_benefit_from_product(product)
					+ this.compute_benefit_from_deal(deal) - deal.bonus;
			System.out.print(" new benefit = " + new_benefit + "\n");

		} else {
			System.out.print(" new benefit = " + deal.bonus + "\n");
		}

	}
}
